package conceptmaniax.hotelapp.util.sync;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;

import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.StatusLine;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.params.ConnManagerParams;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;

import android.app.Activity;
import android.os.Handler;
import android.util.Log;
import conceptmaniax.hotelapp.config.Constants;

public class FileSyncUtils {
	
	private static final float DOWNLOAD_ZIP_FILE_WEIGHT = 0.90f;
	private static final float UNZIP_ZIP_FILE_WEIGHT = 0.05f;
	private static final float DOWNLOAD_DATABASE_FILE_WEIGHT = 0.05f;
	
	private static final int DOWNLOAD_ZIP_FILE_PROGRESS = 0;
	private static final int UNZIP_ZIP_FILE_PROGRESS = 90;
	private static final int DOWNLOAD_DATABASE_FILE_PROGRESS = 95;
	
	
	public static boolean createDir(File dir) throws IOException {
		if (!dir.exists()) {
			return dir.mkdirs();
		}
		
		return true;
	}
	
	public static boolean deleteFile(File file) throws IOException{
		if (file.isDirectory()) {
			for (File f : file.listFiles()) {
				deleteFile(f);
			}
		}
		
		return file.delete();
	}
	
	public static void copyFile(InputStream in, OutputStream out) throws IOException {
		byte[] buffer = new byte[1024];
		int read;
		while((read = in.read(buffer)) != -1){
			out.write(buffer, 0, read);
	    }
	    
		out.flush();
		out.close();
		in.close();
	}
	
	public static void unpackZip(String path, String zipname) throws IOException {       
	     InputStream is = new FileInputStream(path + File.separator + zipname);
	     ZipInputStream zis = new ZipInputStream(new BufferedInputStream(is));

	     String filename;
	     ZipEntry ze;
	     int bytesRead;
	     byte[] buffer = new byte[1024];
	     while ((ze = zis.getNextEntry()) != null) {
	    	 filename = ze.getName();
	    	 if (ze.isDirectory()) {
	    		 File fmd = new File(path + File.separator + filename);
	             fmd.mkdirs();
	             continue;
	    	 }
	    	 
	         FileOutputStream fout = new FileOutputStream(path + File.separator + filename);

	         while ((bytesRead = zis.read(buffer)) != -1) {
	        	 fout.write(buffer, 0, bytesRead);
	         }

	         fout.close();               
	         zis.closeEntry();
	     }
	     zis.close();
	}
	
	public static void unpackZipWithProgress(Activity activity, Handler progressBarHandler, float weightedPercent, int progress, String path, String zipname) throws IOException {       
	     InputStream is = new FileInputStream(path + File.separator + zipname);
	     ZipInputStream zis = new ZipInputStream(new BufferedInputStream(is));
	     ZipFile zipfile = new ZipFile(path + File.separator + zipname);
	
	     String filename;
	     ZipEntry ze;
	     int bytesRead;
	     int counter = 0;
	     byte[] buffer = new byte[1024];
	     WriteListener writeListener = new ProgressWriteListener(activity, progressBarHandler, weightedPercent, progress, zipfile.size());
	     while ((ze = zis.getNextEntry()) != null) {
	    	 filename = ze.getName();
	    	 if (ze.isDirectory()) {
	    		 File fmd = new File(path + File.separator + filename);
	             fmd.mkdirs();
	             continue;
	    	 }

	         FileOutputStream fout = new FileOutputStream(path + File.separator + filename);
	         while ((bytesRead = zis.read(buffer)) != -1) {
	        	 fout.write(buffer, 0, bytesRead);
	         }

	         fout.close();               
	         zis.closeEntry();
	         
	         writeListener.registerWrite(++counter);
	     }
	     zis.close();
	}
	
	public static void downloadAndSaveFile(Activity activity, Handler progressBarHandler, float weightedPercent, int progress, String url, String outFile) throws Exception {
        final HttpClient httpclient = new DefaultHttpClient();
        final HttpParams httpParams = httpclient.getParams();
		
	    HttpConnectionParams.setConnectionTimeout(httpParams, Constants.CONNECTION_TIMEOUT);
		HttpConnectionParams.setSoTimeout(httpParams, Constants.SOCKET_TIMEOUT);
		ConnManagerParams.setTimeout(httpParams, Constants.CONNECTION_TIMEOUT);
		final HttpGet httpGet = new HttpGet(url);
		final HttpResponse response = httpclient.execute(httpGet);
		StatusLine statusLine = response.getStatusLine();
		if (statusLine.getStatusCode() == HttpStatus.SC_OK) {
			FileOutputStream out = new FileOutputStream(outFile);
			CustomHttpEntity customHttpEntity = new CustomHttpEntity(response.getEntity());
			customHttpEntity.setWriteListener(new ProgressWriteListener(activity, progressBarHandler, weightedPercent, progress, customHttpEntity.getContentLength()));
			customHttpEntity.writeTo(out);
			out.close();
		} else {
			response.getEntity().getContent().close();
			throw new Exception(statusLine.getReasonPhrase());
		}
	}
	
	public static void downloadAndSaveImages(Activity activity, Handler progressBarHandler, String versionFromNetwork, String imagesZipFileName) throws Exception {
		try {
			// create images dir if not exists
			createDir(new File(activity.getFilesDir().getAbsolutePath() + File.separator + Constants.IMAGES_FOLDER));
		
			// copy from network
			downloadAndSaveFile(activity, progressBarHandler, DOWNLOAD_ZIP_FILE_WEIGHT, DOWNLOAD_ZIP_FILE_PROGRESS, Constants.FILE_URL + File.separator + versionFromNetwork + File.separator + imagesZipFileName, activity.getFilesDir().getAbsolutePath() + File.separator + Constants.IMAGES_FOLDER + File.separator + imagesZipFileName);
		
			// unpack zip
			unpackZipWithProgress(activity, progressBarHandler, UNZIP_ZIP_FILE_WEIGHT, UNZIP_ZIP_FILE_PROGRESS, activity.getFilesDir().getAbsolutePath() + File.separator + Constants.IMAGES_FOLDER, imagesZipFileName);
		} finally {
			// delete zip file
			try {
				FileSyncUtils.deleteFile(new File(activity.getFilesDir().getAbsolutePath() + File.separator + Constants.IMAGES_FOLDER + File.separator + imagesZipFileName));
			} catch (Exception e) { 
				// cannot do anything at this point
			}
		}
	}
	
	public static void downloadAndSaveDatabase(Activity activity, Handler progressBarHandler, String versionFromNetwork, String databaseFileName) throws Exception {
		// create database if not exists
		createDir(new File(activity.getDatabasePath(Constants.DATABASE_NAME).getParent()));

		// copy from network
		downloadAndSaveFile(activity, progressBarHandler, DOWNLOAD_DATABASE_FILE_WEIGHT, DOWNLOAD_DATABASE_FILE_PROGRESS, Constants.FILE_URL + File.separator + versionFromNetwork + File.separator + databaseFileName, activity.getDatabasePath(Constants.DATABASE_NAME).getAbsolutePath());
	}
	
	public static void copyImagesFromAssets(Activity activity) throws Exception {
		try {
			// create images dir if not exists
			createDir(new File(activity.getFilesDir().getAbsolutePath() + File.separator + Constants.IMAGES_FOLDER));
		
			// copy images from assets
			final InputStream myInput = activity.getAssets().open(Constants.IMAGES_ZIP_FILE_NAME);
			final OutputStream myOutput = new FileOutputStream(new File(activity.getFilesDir().getAbsolutePath() + File.separator + Constants.IMAGES_FOLDER + File.separator + Constants.IMAGES_ZIP_FILE_NAME));

			FileSyncUtils.copyFile(myInput, myOutput);
		
			// unpack zip
			unpackZip(activity.getFilesDir().getAbsolutePath() + File.separator + Constants.IMAGES_FOLDER, Constants.IMAGES_ZIP_FILE_NAME);
		} finally {
			// delete zip file
			try {
				FileSyncUtils.deleteFile(new File(activity.getFilesDir().getAbsolutePath() + File.separator + Constants.IMAGES_FOLDER + File.separator + Constants.IMAGES_ZIP_FILE_NAME));
			} catch (Exception e) { 
				// cannot do anything at this point
			}
		}
	}
}
